package service

import (
	"helper-api/app/models/entity"
	"helper-api/app/models/request"
	"helper-api/app/models/response"
	"helper-api/core"
	"os/exec"
	"strconv"
	"time"
)

var Server = new(ScriptService)

type ScriptService struct{}

// Tree 服务Tree
func (s *ScriptService) Tree(param *request.ScriptTreeRequest) ([]response.ScriptTreeResponse, *response.BusinessError) {
	var (
		result []response.ScriptTreeResponse
		filter = func(list []response.ScriptTreeResponse, pId int64) []response.ScriptTreeResponse {
			var result = make([]response.ScriptTreeResponse, 0)
			for _, item := range list {
				if item.ParentId == pId {
					result = append(result, item)
				}
			}
			return result
		}
		buildTree func(list []response.ScriptTreeResponse, target *response.ScriptTreeResponse) // 匿名递归函数定义
		root      = response.ScriptTreeResponse{
			Id:       0,
			ParentId: 0,
			Title:    "全部",
			ItemType: 0,
			IsLeaf:   false,
			Children: nil,
		}
		err error
	)

	// 递归构建tree
	buildTree = func(list []response.ScriptTreeResponse, target *response.ScriptTreeResponse) {
		nodes := filter(list, target.Id)
		if len(nodes) > 0 {
			target.Children = nodes
			target.IsLeaf = false
			for i := 0; i < len(nodes); i++ {
				buildTree(list, &nodes[i])
			}
		} else {
			target.IsLeaf = true
		}
	}

	if param.Id == -1 {
		// 获取所有分组
		if err = core.DB.Model(&entity.Script{}).
			Select("id, title, item_type, parent_id, 0 as is_leaf").
			Where("can_view = 1").
			Order("create_time").
			Find(&result).
			Error; err != nil {
			core.Log.Error("执行SQL错误 => %s", err.Error())
			return nil, response.NewBusinessError(response.ScriptGetError)
		}
		// 构建Tree数据
		if param.IsTree {
			if param.ExpendRoot {
				buildTree(result, &root)
				return []response.ScriptTreeResponse{root}, nil
			} else {
				root := filter(result, 0)
				for i := 0; i < len(root); i++ {
					buildTree(result, &root[i])
				}
				return root, nil
			}
		}
	} else {
		if err = core.DB.Debug().Model(&entity.Script{}).
			Select("id, title, item_type, parent_id, ifnull((select 0 from s_script ss where ss.parent_id = s_script.id), 1) as is_leaf").
			Where("can_view = 1 and parent_id = ?", param.Id).
			Order("create_time").Find(&result).
			Error; err != nil {
			core.Log.Error("执行SQL错误 => %s", err.Error())
			return nil, response.NewBusinessError(response.ScriptGetError)
		}
	}
	return result, nil
}

// GroupCreate 分组创建
func (s *ScriptService) GroupCreate(param *request.ServerGroupCreateRequest) (*response.ScriptTreeResponse, *response.BusinessError) {
	var (
		server *entity.Script
		total  int64
		err    error
	)
	if err = core.DB.Model(&entity.Script{}).
		Where("title = ? or work_home = ?", param.Title, param.WorkHome).
		Count(&total).
		Error; err != nil {
		core.Log.Error("执行SQL错误 => %s", err.Error())
		return nil, response.NewBusinessError(response.DataNotExist)
	}
	if total > 0 {
		core.Log.Error("存在相同的分组名或者工作路径")
		return nil, response.NewBusinessError(response.ExistSameData)
	}

	server = &entity.Script{
		ItemType:   1,
		ParentId:   0,
		Title:      param.Title,
		CurrPath:   "0",
		Desc:       param.Desc,
		WorkHome:   param.WorkHome,
		CreateId:   param.UserId,
		CreateTime: time.Now(),
		CanView:    1,
	}
	if err = core.DB.Create(server).Error; err != nil {
		core.Log.Error("执行SQL错误 => %s", err.Error())
		return nil, response.NewBusinessError(response.ScriptGroupCreateError)
	}

	core.Log.Info("创建分组成功 => %v", server)
	return &response.ScriptTreeResponse{
		Id:       server.Id,
		ParentId: 0,
		Title:    server.Title,
		ItemType: server.ItemType,
		IsLeaf:   true,
	}, nil
}

// GroupUpdate 分组更新
func (s *ScriptService) GroupUpdate(param *request.ScriptGroupUpdateRequest) (*response.ScriptTreeResponse, *response.BusinessError) {
	var (
		isUpdate = false
		server   entity.Script
		total    int64
		err      error
	)
	if err = core.DB.Model(&entity.Script{}).
		Where("id = ? and can_view = 1", param.Id).
		First(&server).
		Error; err != nil {
		core.Log.Error("执行SQL错误 => %s", err.Error())
		return nil, response.NewBusinessError(response.DataNotExist)
	}
	if server.Id == 0 {
		core.Log.Error("数据查询不存在")
		return nil, response.NewBusinessError(response.DataNotExist)
	}
	if param.Title != server.Title {
		server.Title = param.Title
		isUpdate = true
	}
	if param.Desc != server.Desc {
		server.Desc = param.Desc
		isUpdate = true
	}
	if param.WorkHome != server.WorkHome {
		// TODO 后续是否需要修改工作路径
		server.WorkHome = param.WorkHome
		isUpdate = true
	}
	if isUpdate {
		server.UpdateId, server.UpdateTime = param.Id, time.Now()
		if err = core.DB.Save(&server).Error; err != nil {
			core.Log.Error("更新数据失败 => %s", err.Error())
			return nil, response.NewBusinessError(response.DateUpdateError)
		}
	} else {
		core.Log.Error("不需要更新数据")
		return nil, response.NewBusinessError(response.DataNotNeedUpdate)
	}

	if err = core.DB.Model(&entity.Script{}).
		Where("can_view = 1 and parent_id = ?", server.Id).
		Count(&total).
		Error; err != nil {
		core.Log.Error("获取当前分组的子节点数据失败: %s", err.Error())
	}

	return &response.ScriptTreeResponse{
		Id:       server.Id,
		ParentId: 0,
		Title:    server.Title,
		ItemType: server.ItemType,
		IsLeaf:   total <= 0,
	}, nil
}

// GroupList 分组列表
func (s *ScriptService) GroupList() ([]response.ScriptGroupListResponse, *response.BusinessError) {
	var (
		result []response.ScriptGroupListResponse
		err    error
	)
	if err = core.DB.Model(&entity.Script{}).
		Select("id, title, item_type, desc, work_home, create_id, create_time, (select s_user.username from s_user where s_user.id = s_script.create_id) as create_name").
		Where("can_view = 1 and parent_id = 0").
		Order("create_time").
		Find(&result).
		Error; err != nil {
		core.Log.Error("查询数据失败 => %s", err.Error())
		return nil, response.NewBusinessError(response.GetDataError)
	}
	return result, nil
}

// ServerList 分组下的服务列表
func (s *ScriptService) ServerList(gId int64) ([]response.ScriptItemListResponse, *response.BusinessError) {
	var (
		result []response.ScriptItemListResponse
		err    error
	)
	if err = core.DB.Model(&entity.Script{}).
		Select("s_script.id,s_script.parent_id as group_id,b.title as group_name,b.work_home,s_script.item_type,s_script.title,s_script.desc,s_script.work_path,s_script.create_id,\n    (select s_user.username from s_user where s_user.id = s_script.create_id) as create_name,s_script.create_time").
		Joins("left join s_script b on b.id = s_script.parent_id").
		Where("s_script.parent_id = ? and s_script.can_view = 1 and s_script.item_type = 2", gId).
		First(&result).
		Error; err != nil {
		core.Log.Error("执行分组SQL错误 => %s", err.Error())
		return nil, response.NewBusinessError(response.ScriptItemGetError)
	}
	return result, nil
}

// GroupDelete 分组删除
func (s *ScriptService) GroupDelete(ids []int64, userId int64) *response.BusinessError {
	if err := core.DB.Model(&entity.Script{}).
		Where("can_view = 1 and id in ?", ids).
		Updates(map[string]any{"can_view": 0, "update_time": time.Now(), "update_id": userId}).
		Error; err != nil {
		return response.NewBusinessError(response.ScriptGroupDeleteError)
	}
	return nil
}

// ServerCreate 服务创建
func (s *ScriptService) ServerCreate(param *request.ScriptItemCreateRequest) (*response.ScriptTreeResponse, *response.BusinessError) {
	var (
		server *entity.Script
		total  int64
		err    error
	)
	if err = core.DB.Model(&entity.Script{}).
		Where("(title = ? or work_home = ?) and parent_id = ?", param.Title, param.WorkPath, param.ParentId).
		Count(&total).
		Error; err != nil {
		core.Log.Error("执行SQL错误 => %s", err.Error())
		return nil, response.NewBusinessError(response.SqlExecuteError)
	}
	if total > 0 {
		core.Log.Error("存在相同的服务名或者工作目录 => %s", err.Error())
		return nil, response.NewBusinessError(response.ExistSameData)
	}

	server = &entity.Script{
		ItemType:   2,
		ParentId:   param.ParentId,
		Title:      param.Title,
		CurrPath:   "0-" + strconv.FormatInt(param.ParentId, 10),
		Desc:       param.Desc,
		WorkPath:   param.WorkPath,
		CreateId:   param.UserId,
		CreateTime: time.Now(),
		CanView:    1,
	}
	if err = core.DB.Create(server).Error; err != nil {
		core.Log.Error("执行SQL错误 => %s", err.Error())
		return nil, response.NewBusinessError(response.SqlExecuteError)
	}
	core.Log.Info("创建服务成功 => %v", server)
	return &response.ScriptTreeResponse{
		Id:       server.Id,
		ParentId: server.ParentId,
		Title:    server.Title,
		ItemType: server.ItemType,
	}, nil
}

// ServerUpdate 服务更新
func (s *ScriptService) ServerUpdate(param *request.ServerItemUpdateRequest) (*response.ScriptTreeResponse, *response.BusinessError) {
	var (
		isUpdate = false
		server   entity.Script
		err      error
	)
	if err = core.DB.Model(&entity.Script{}).
		Where("id = ? and can_view = 1", param.Id).
		First(&server).
		Error; err != nil {
		core.Log.Error("执行SQL错误 => %s", err.Error())
		return nil, response.NewBusinessError(response.SqlExecuteError)
	}
	if server.Id == 0 {
		core.Log.Error("数据查询不存在")
		return nil, response.NewBusinessError(response.DataNotExist)
	}
	if param.Title != server.Title {
		server.Title = param.Title
		isUpdate = true
	}
	if param.Desc != server.Desc {
		server.Desc = param.Desc
		isUpdate = true
	}
	if param.WorkPath != server.WorkPath {
		// TODO 后续是否需要修改工作路径
		server.WorkPath = param.WorkPath
		isUpdate = true
	}
	if isUpdate {
		server.UpdateId, server.UpdateTime = param.Id, time.Now()
		if err = core.DB.Save(&server).Error; err != nil {
			core.Log.Error("更新数据失败 => %s", err.Error())
			return nil, response.NewBusinessError(response.DateUpdateError)
		}
	} else {
		core.Log.Error("不需要更新数据")
		return nil, response.NewBusinessError(response.DataNotNeedUpdate)
	}

	return &response.ScriptTreeResponse{
		Id:       server.Id,
		ParentId: server.ParentId,
		Title:    server.Title,
		ItemType: server.ItemType,
	}, nil
}

// ScriptList 脚本列表
func (s *ScriptService) ScriptList(sId uint64) ([]response.ServerScriptListResponse, *response.BusinessError) {
	var (
		result []response.ServerScriptListResponse
		server entity.Script
		group  entity.Script
		err    error
	)
	if err = core.DB.Model(&entity.Script{}).
		Where("can_view = 1 and id = ?", sId).
		First(&server).
		Error; err != nil {
		core.Log.Error("执行分组SQL错误 => %s", err.Error())
		return nil, response.NewBusinessError(response.SqlExecuteError)
	}
	if server.Id == 0 {
		core.Log.Error("当前服务不存在")
		return nil, response.NewBusinessError(response.DataNotExist)
	}

	if err = core.DB.Model(&entity.Script{}).
		Where("can_view = 1 and id = ?", server.ParentId).
		First(&group).
		Error; err != nil {
		core.Log.Error("执行分组SQL错误 => %s", err.Error())
		return nil, response.NewBusinessError(response.SqlExecuteError)
	}
	if group.Id == 0 {
		core.Log.Error("当前分组不存在")
		return nil, response.NewBusinessError(response.DataNotExist)
	}

	if err = core.DB.Model(&entity.Script{}).
		Select("id", "item_type", "curr_path", "title", "desc", "work_home", "work_path", "file_name", "content", "script_type", "script_param", "log_file", "create_id", "create_time").
		Where("can_view = 1 and item_type = 3 and parent_id = ?", sId).
		Find(&result).
		Error; err != nil {
		core.Log.Error("执行SQL错误 => %s", err.Error())
		return nil, response.NewBusinessError(response.SqlExecuteError)
	}
	if len(result) > 0 {
		for i := 0; i < len(result); i++ {
			result[i].WorkHome = group.WorkHome
			result[i].WorkPath = server.WorkPath
			result[i].WorkHome = group.WorkHome
			result[i].GroupId = group.Id
			result[i].GroupName = group.Title
			result[i].ServerId = server.Id
			result[i].ServerName = server.Title
		}
	}
	return result, nil
}

// ScriptCreate 创建
func (s *ScriptService) ScriptCreate(param *request.ServerScriptCreateRequest) (*response.ServerScriptListResponse, *response.BusinessError) {
	var (
		server entity.Script
		group  entity.Script
		script entity.Script
		err    error
	)
	if err = core.DB.Model(&entity.Script{}).
		Where("can_view = 1 and id = ?", param.ServerId).
		First(&server).
		Error; err != nil {
		core.Log.Error("执行分组SQL错误 => %s", err.Error())
		return nil, response.NewBusinessError(response.SqlExecuteError)
	}
	if server.Id == 0 {
		core.Log.Error("当前服务不存在")
		return nil, response.NewBusinessError(response.DataNotExist)
	}

	if err = core.DB.Model(&entity.Script{}).
		Where("can_view = 1 and id = ?", server.ParentId).
		First(&group).
		Error; err != nil {
		core.Log.Error("执行分组SQL错误 => %s", err.Error())
		return nil, response.NewBusinessError(response.SqlExecuteError)
	}
	if group.Id == 0 {
		core.Log.Error("当前分组不存在")
		return nil, response.NewBusinessError(response.DataNotExist)
	}

	script = entity.Script{
		ItemType:    3,
		ParentId:    param.ServerId,
		Title:       param.Title,
		CurrPath:    server.CurrPath + "-" + strconv.FormatInt(server.Id, 10),
		Desc:        param.Desc,
		WorkHome:    group.WorkHome,
		WorkPath:    server.WorkHome,
		FileName:    param.FilePath,
		Content:     param.Content,
		ScriptType:  param.ScriptType,
		ScriptParam: param.ScriptParam,
		LogFile:     param.LogFile,
		CreateId:    param.UserId,
		CreateTime:  time.Now(),
		CanView:     1,
	}
	if err = core.DB.Create(&script).Error; err != nil {
		core.Log.Error("执行SQL错误 => %s", err.Error())
		return nil, response.NewBusinessError(response.SqlExecuteError)
	}
	core.Log.Info("创建服务成功 => %v", server)
	return &response.ServerScriptListResponse{
		Id:          server.Id,
		GroupId:     group.Id,
		GroupName:   group.Title,
		ServerId:    server.Id,
		ServerName:  server.Title,
		Desc:        script.Desc,
		Title:       server.Title,
		ItemType:    server.ItemType,
		CurrPath:    script.CurrPath,
		WorkHome:    script.WorkHome,
		WorkPath:    script.WorkPath,
		FileName:    script.FileName,
		Content:     script.Content,
		ScriptType:  script.ScriptType,
		ScriptParam: script.ScriptParam,
		LogFile:     script.LogFile,
		CreateId:    script.CreateId,
		CreateTime:  script.CreateTime,
	}, nil
}

func (s *ScriptService) ScriptExecute(id uint64, userId uint64) *response.BusinessError {
	var (
		cmd    *exec.Cmd
		server entity.Script
		err    error
	)
	if err = core.DB.Model(&entity.Script{}).
		Where("can_view = 1 and id = ?", id).
		First(&server).
		Error; err != nil {
		core.Log.Error("获取脚本 => %s", err.Error())
		return response.NewBusinessError(response.SqlExecuteError)
	}
	if server.Id == 0 {
		return response.NewBusinessError(response.DataNotExist)
	}
	// 开始执行shell命令
	cmd = exec.Command("bash", "-c", server.Content)
	_ = cmd.Start()
	return nil
}
